package com.dingreading.cloud.mall.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.dingreading.cloud.common.util.AccountUtil;
import com.dingreading.cloud.common.util.EnumType;
import com.dingreading.cloud.common.util.PageUtil;
import com.dingreading.cloud.common.util.QueryFiledUtil;
import com.dingreading.cloud.mall.dto.OrderFormDto;
import com.dingreading.cloud.mall.entity.DeliveryAddress;
import com.dingreading.cloud.mall.entity.OrderForm;
import com.dingreading.cloud.mall.entity.table.OrderFormTableDef;
import com.dingreading.cloud.mall.mapper.OrderFormMapper;
import com.dingreading.cloud.mall.service.OrderFormService;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryCondition;
import com.mybatisflex.core.query.QueryMethods;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.update.UpdateChain;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.dingreading.cloud.mall.entity.table.ShopCartTableDef.shopCart;


/**
 * 服务层实现。
 *
 * @author Administrator
 * @since 2023-11-22
 */
@Service
public class OrderFormServiceImpl extends BaseServiceImpl<OrderFormMapper, OrderForm, OrderFormTableDef> implements OrderFormService {

    @Override
    protected OrderFormTableDef getTable() {
        return OrderFormTableDef.orderForm;
    }

    @Resource
    private OrderFormMapper orderFormMapper;

    @Override
    public Page<OrderForm> pageList(
            PageUtil pageUtil, String storeUid, String staffUid, String keyword, Integer projectType, Integer status,
            Integer roleType, String beginDate, String endDate, String payChannelCode, Integer financeStatus
    ) {
        QueryCondition condition = QueryCondition.createEmpty();
        if (storeUid != null)
            condition.and(table.storeUid.eq(storeUid));
        if (staffUid != null)
            condition.and(table.staffUid.eq(staffUid));
        if (StringUtils.isNotBlank(keyword)) {
            condition.and(table.name.like(keyword)
                    .or(table.code.like(keyword))
                    .or(table.phone.like(keyword))
                    .or(table.storeName.like(keyword))
                    .or(table.address.like(keyword))
                    .or(table.saleStaffName.like(keyword))
                    .or(table.addStaffName.like(keyword))
            );
        }
        if (null != projectType)
            condition.and(table.projectType.eq(projectType));
        if (StringUtils.isNotBlank(payChannelCode))
            condition.and(table.payChannelCode.likeLeft(payChannelCode));

        if (roleType != null) {
            if (roleType.equals(1)) {
                // 仓库
                if (status != null) {
                    condition.and(table.status.eq(status));
                } else {
                    condition.and(table.status.in(EnumType.OrderForm.WAIT_SEND.getType(), EnumType.OrderForm.SENDING.getType(), EnumType.OrderForm.OK.getType()));
                }

                // 去除只有非实体购物车记录的商品订单
                QueryWrapper wrapper = QueryWrapper.create()
                        .select(QueryMethods.distinct(shopCart.code))
                        .from(shopCart)
                        .where(shopCart.realStatus.eq(1));

                condition.and(table.code.in(wrapper));
            } else if (roleType.equals(2)) {
                // 财务
                condition.and(table.status.in(EnumType.OrderForm.WAIT_SEND.getType(), EnumType.OrderForm.SENDING.getType(), EnumType.OrderForm.OK.getType()));
            } else if (roleType.equals(3)) {
                // 经理，只查看自营门店和商城赠品订单
                condition.and(table.corpUid.eq(AccountUtil.SELF_CORP_UID).or(table.projectType.eq(EnumType.BalanceProject.GIFT_GOODS.getType())));
                if (status != null) {
                    condition.and(table.status.eq(status));
                }
            }
        } else {
            if (status != null) {
                condition.and(table.status.eq(status));
            }
        }
        if (null != financeStatus)
            condition.and(table.financeStatus.eq(financeStatus));

        if (StringUtils.isNotBlank(beginDate) && StringUtils.isNotBlank(endDate))
            condition.and(table.addTime.between(QueryFiledUtil.appendMin00(beginDate), QueryFiledUtil.appendMin24(endDate)));

        QueryWrapper wrapper = QueryWrapper.create()
                .where(condition)
                .orderBy(table.id.desc());

        return getMapper().paginate(Page.of(pageUtil.getPage(), pageUtil.getRows()), wrapper);
    }

    @Override
    public OrderForm getByCode(String staffUid, String code) {
        QueryCondition condition = QueryCondition.createEmpty();
        if (staffUid != null)
            condition.and(table.staffUid.eq(staffUid));
        condition.and(table.code.eq(code));
        return getMapper().selectOneByCondition(condition);
    }

    @Override
    public int deleteByStaffIdAndCode(String staffUid, String code) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.staffUid.eq(staffUid))
                .and(table.code.eq(code))
                .and(table.status.notIn(EnumType.OrderForm.OK.getType(),
                        EnumType.OrderForm.WAIT_SEND.getType(),
                        EnumType.OrderForm.SENDING.getType(),
                        EnumType.OrderForm.REFUND.getType()));
        return getMapper().deleteByCondition(condition);
    }

    @Override
    public boolean updateAddress(String staffUid, String code, DeliveryAddress address) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.staffUid.eq(staffUid))
                .and(table.code.eq(code))
                .and(table.status.in(EnumType.OrderForm.WAIT_CONFIRM.getType(), EnumType.OrderForm.WAIT_PAY.getType(), EnumType.OrderForm.APPLY_BANKPAY.getType()));

        return UpdateChain.of(OrderForm.class)
                .set(table.deliveryId, address.getId())
                .set(table.name, address.getName())
                .set(table.phone, address.getPhone())
                .set(table.address, address.getProvinces() + address.getAddress())
                .where(condition)
                .update();
    }

    @Override
    public boolean cancelOrder(String staffUid, String code) {
        QueryCondition condition = QueryCondition.createEmpty();
        if (staffUid != null)
            condition.and(table.staffUid.eq(staffUid));
        condition.and(table.code.eq(code))
                .and(table.status.in(EnumType.OrderForm.WAIT_CONFIRM.getType(), EnumType.OrderForm.WAIT_PAY.getType()));

        return UpdateChain.of(OrderForm.class)
                .set(table.status, EnumType.OrderForm.CANCEL.getType())
                .set(table.statusName, EnumType.OrderForm.CANCEL.getName())
                .where(condition)
                .update();
    }

    @Override
    public boolean payOkGoodsOrder(
            String staffUid, String code, Integer payType, String tradeType, String payId, String tradeNo, Integer payOnline, String payTime
    ) {
        QueryCondition condition = QueryCondition.createEmpty();
        if (staffUid != null)
            condition.and(table.staffUid.eq(staffUid));
        condition.and(table.code.eq(code));
        condition.and(table.status.in(EnumType.OrderForm.WAIT_CONFIRM.getType(), EnumType.OrderForm.WAIT_PAY.getType())
                .or(table.payChannelCode.eq(EnumType.PayChannelCode.BANK.getType()).and(table.status.eq(EnumType.OrderForm.APPLY_BANKPAY.getType())))
        );

        int waitSendType = EnumType.OrderForm.WAIT_SEND.getType();
        String waitSendName = EnumType.OrderForm.WAIT_SEND.getName();

        UpdateChain<OrderForm> update = UpdateChain.of(OrderForm.class);
        update.set(table.payType, payType)
                .set(table.tradeType, tradeType)
                .set(table.payTime, payTime)
                .set(table.buyerId, payId)
                .set(table.tradeNo, tradeNo)
                .set(table.status, waitSendType)
                .set(table.statusName, waitSendName);
        if (payOnline.equals(1)) {
            // 线上付款，财务审核状态默认系统审核通过
            update.set(table.financeStatus, EnumType.OrderForm.SYSTEM_CHECK_OK.getType())
                    .set(table.financeStatusName, EnumType.OrderForm.SYSTEM_CHECK_OK.getName());
        }
        return update.where(condition).update();
    }

    @Override
    public boolean payOkGiftGoodsOrder(String staffUid, String code, Integer payType, String tradeType, String payChannelCode, String payTime) {
        QueryCondition condition = QueryCondition.createEmpty();
        if (staffUid != null)
            condition.and(table.staffUid.eq(staffUid));
        condition.and(table.code.eq(code));
        condition.and(table.status.in(EnumType.OrderForm.WAIT_CONFIRM.getType(), EnumType.OrderForm.WAIT_PAY.getType()));

        int waitSendType = EnumType.OrderForm.WAIT_SEND.getType();
        String waitSendName = EnumType.OrderForm.WAIT_SEND.getName();

        UpdateChain<OrderForm> update = UpdateChain.of(OrderForm.class);
        update.set(table.payType, payType)
                .set(table.tradeType, tradeType)
                .set(table.payChannelCode, payChannelCode)
                .set(table.payTime, payTime)
                .set(table.status, waitSendType)
                .set(table.statusName, waitSendName)
                // 线上付款，财务审核状态默认系统审核通过
                .set(table.financeStatus, EnumType.OrderForm.SYSTEM_CHECK_OK.getType())
                .set(table.financeStatusName, EnumType.OrderForm.SYSTEM_CHECK_OK.getName());
        return update.where(condition).update();
    }

    @Override
    public Integer getFormStatus(String staffUid, String code) {
        QueryCondition condition = QueryCondition.createEmpty();
        if (staffUid != null)
            condition.and(table.staffUid.eq(staffUid));
        condition.and(table.code.eq(code));

        QueryWrapper wrapper = QueryWrapper.create()
                .select(table.status)
                .where(condition);
        return getMapper().selectObjectByQueryAs(wrapper, Integer.class);
    }

    @Override
    public Map<String, String> getStatusNum(String storeUid, String staffUid) {
        List<JSONObject> list = orderFormMapper.getStatusNum(storeUid, staffUid);

        Map<String, String> result = new HashMap<>();
        result.put("ok", "0");
        result.put("confirm", "0");
        result.put("pay", "0");
        result.put("cancel", "0");
        result.put("send", "0");

        if (CollectionUtils.isNotEmpty(list)) {
            for (JSONObject jsonObject : list) {
                String num = jsonObject.getString("num");
                String status = jsonObject.getString("status");
                String statusName = jsonObject.getString("statusName");
                result.put(statusName, num);
            }
        }
        return result;
    }

    @Override
    public void updatePayChannelCode(String staffUid, String code, String payChannelCode) {
        QueryCondition condition = QueryCondition.createEmpty();
        if (staffUid != null)
            condition.and(table.staffUid.eq(staffUid));
        condition.and(table.code.eq(code));

        UpdateChain.of(OrderForm.class)
                .set(table.payChannelCode, payChannelCode)
                .where(condition)
                .update();
    }

    @Override
    public void updatePayChannelCodeAndCorpPay(String staffUid, String code, String payChannelCode) {
        QueryCondition condition = QueryCondition.createEmpty();
        if (staffUid != null)
            condition.and(table.staffUid.eq(staffUid));
        condition.and(table.code.eq(code));

        UpdateChain.of(OrderForm.class)
                .set(table.payChannelCode, payChannelCode)
                .where(condition)
                .update();
    }

    @Override
    public boolean applyBankPay(String storeUid, String code, String payTime) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.storeUid.eq(storeUid))
                .and(table.code.eq(code))
                .and(table.status.eq(EnumType.OrderForm.WAIT_PAY.getType()));

        String channelCode = EnumType.PayChannelCode.BANK.getType();
        int applyBankpayType = EnumType.OrderForm.APPLY_BANKPAY.getType();
        String applyBankpayName = EnumType.OrderForm.APPLY_BANKPAY.getName();
        int financeCheckWaitType = EnumType.OrderForm.FINANCE_CHECK_WAIT.getType();
        String financeCheckWaitName = EnumType.OrderForm.FINANCE_CHECK_WAIT.getName();

        return UpdateChain.of(OrderForm.class)
                .set(table.payChannelCode, channelCode)
                .set(table.payTime, payTime)
                .set(table.status, applyBankpayType)
                .set(table.statusName, applyBankpayName)
                .set(table.financeStatus, financeCheckWaitType)
                .set(table.financeStatusName, financeCheckWaitName)
                .where(condition)
                .update();
    }

    @Override
    public boolean cancelBankPay(String storeUid, String code) {
        QueryCondition condition = QueryCondition.createEmpty();
        if (StringUtils.isNotBlank(storeUid))
            condition.and(table.storeUid.eq(storeUid));
        condition.and(table.code.eq(code))
                .and(table.status.eq(EnumType.OrderForm.APPLY_BANKPAY.getType()));

        int waitPayType = EnumType.OrderForm.WAIT_PAY.getType();
        String waitPayName = EnumType.OrderForm.WAIT_PAY.getName();

        return UpdateChain.of(OrderForm.class)
                .set(table.payChannelCode, "")
                .set(table.payTime, "")
                .set(table.status, waitPayType)
                .set(table.statusName, waitPayName)
                .where(condition)
                .update();
    }

    @Override
    public Page<OrderFormDto> staffPageList(PageUtil pageUtil, String storeUid, String staffUid, String keyword, Integer status) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.storeUid.eq(storeUid))
                .and(table.staffUid.eq(staffUid));
        if (StringUtils.isNotBlank(keyword))
            condition.and(table.name.like(keyword)
                    .or(table.code.like(keyword))
                    .or(table.phone.like(keyword))
                    .or(table.storeName.like(keyword))
            );
        if (status != null)
            condition.and(table.status.eq(status));

        QueryWrapper wrapper = QueryWrapper.create()
                .select(table.allColumns)
                .from(table)
                .where(condition)
                .orderBy(table.id.desc());

        return getMapper().paginateAs(Page.of(pageUtil.getPage(), pageUtil.getRows()), wrapper, OrderFormDto.class);
    }

}
